package source_api

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)
import "github.com/imroc/req"
import "github.com/PuerkitoBio/goquery"

const CAS_LOGIN_URL = "https://authserver.zcst.edu.cn/cas/login"
const DK_URL = "https://diankong.jluzh.edu.cn/App/index.aspx"
const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0"

var once sync.Once
var electricSessionInstance *ElectricSession

//保存维持电控登录状态的必要信息，
//使用个人账号代理查询，避免登录压力过大
type ElectricSession struct {
	UserName string
	Password string
	Cookie   string
}

func GetElectricSessionInstance() *ElectricSession {
	once.Do(func() {
		electricSessionInstance = &ElectricSession{UserName: os.Getenv("USERNAME"), Password: os.Getenv("PASSWORD")}
	})

	return electricSessionInstance
}

func (s *ElectricSession) Login() (e error) {
	cookie := new(http.Cookie) //保持登录CAS过程Cookie

	modReq := req.New()

	//自定义Req Client，解决自动重定向问题
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}
	modReq.SetClient(client)

	//GET获取CSRF Token [execution]
	getCsrfTokenResp, _ := req.Get(CAS_LOGIN_URL, req.Param{ //Todo: 处理这里的错误
		"service": DK_URL,
	}, cookie)

	//通过套接字流创建文档
	doc, getCsrfTokenBytesErr := goquery.NewDocumentFromReader(bytes.NewReader(getCsrfTokenResp.Bytes()))

	if getCsrfTokenBytesErr != nil {
		return errors.New("read csrf token bytes failed")
	}

	//读取文档token
	execution, exists := doc.Find("input[name=\"execution\"]").First().Attr("value") //CSRF Token

	if !exists {
		return errors.New("document page csrf token not exists")
	}

	//POST登录请求
	loginResp, _ := modReq.Post(CAS_LOGIN_URL, req.Header{
		"User-Agent": USER_AGENT,
	}, req.QueryParam{
		"service": DK_URL,
	}, req.Param{
		"username":   s.UserName,
		"password":   s.Password,
		"rememberMe": "true",
		"execution":  execution,
		"_eventId":   "submit",
		"loginType":  "1",
		"submit":     "登 录",
	}, cookie)

	casRedirectTo := loginResp.Response().Header.Get("Location") //带登录ticket的电控url

	dkLoginResp, getTargetCookieErr := modReq.Get(casRedirectTo, req.Header{
		"User-Agent": USER_AGENT,
	})

	if getTargetCookieErr != nil {
		return errors.New("diankong login failed")
	}

	cookies := dkLoginResp.Response().Header["Set-Cookie"]
	if len(cookies) != 0 {
		s.Cookie = dkLoginResp.Response().Header["Set-Cookie"][0] //save diankong Cookie
	} else {
		return errors.New("diankong didn't return Set-Cookie")
	}

	return
}

//检查登录是否存活
func (s *ElectricSession) IsAlive() {

}

//定时调用，检查是否掉线，若掉，重新登录
func (s *ElectricSession) RefreshStatus(ticker <-chan time.Time) {
	for {
		<-ticker
		fmt.Println("tick")
		loginErr := s.Login()
		if loginErr != nil {
			for i := 0; i < 10; i++ { //Todo: 速度太快了，需要延迟，不然可能会被WAP拦截
				if s.Login() == nil {
					break
				}
				print("retry login failed time:" + strconv.FormatInt(int64(i), 10))
			}
			print("after retry login failed, return")
			os.Exit(-1)
		}
	}
}
